/**
 *
 * @Author: Marek Zakowicz <mazak (at) debian (dot) linux.org.pl>
 *
 * Copyright (c) 2005, 2006, 2007 Marek Zakowicz. All rights reserved.
 *
 * Licence: This code may be used, (re)distribute and/or modify under the terms one of the following two kinds of licence:
 *          1) as free software under GPL 3 (General Public Licence ver. 3 as published by the Free Software Foundation)
 *          2) as software under the terms individual licence from Marek Zakowicz
 *
 *          This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *          without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

package jsp2php;

import java.util.LinkedList;
import static jsp2php.StatementType.*;

/**
 * @navassoc - type - StatementType
 * @opt attributes
 * @opt types
 */
class StatementStackItem {
   String        label;
   StatementType type;
   boolean       completed;

   StatementStackItem(String label, StatementType type, boolean completed) {
      this.label     = label;
      this.type      = type;
      this.completed = completed;
   }

   public String toString() {
      return "<"+ label +", "+ type +", "+ completed +">";
   }
}

/**
 * StatementStack prepare base to process java (espessialy labeled) statements regards to jsp requirement of partitioning code blocks between many scriptlets.
 * @composed 1 stack * StatementStackItem
 * @opt all
 */
class StatementStack {

   private LinkedList<StatementStackItem> stack = new LinkedList<StatementStackItem>();

   void stBegin(String label, StatementType type, boolean completed) {
      debug("begin ("+ label +", "+ type +", "+ completed +")");

      StatementStackItem first = peek();
      if( first!=null && !first.completed && label==null) {
         if( first.type == LABEL ) {
            first.type      = type;
            first.completed = completed;
            return;
         }
         if( type==BLOCK && (first.type==LOOP || first.type==IF || first.type==ELSE || first.type==SWITCH) ) {
            first.completed = true;
            return;
         }
      }
      StatementStackItem i = new StatementStackItem(label, type, completed);
      stack.addFirst( i );

      debug("begin-add: " + i );
   }

   void stEnd() {
      debug("end");

      StatementStackItem first = peek();
      /*
      if( first==null ) {
         if( type!=null ) { // BLOCK?
            throw new TranslatorException("Statment finished - expected "+ type +", but not found any statement!");
         }
         return;
      }
      if( first.type!=type ) {
         throw new TranslatorException("Statement finished - expected "+ type +", but "+ first.type +" found!");
      }
      */
      boolean lastCompleted=false, curCompleted=false;
      while(first!=null && !lastCompleted && !curCompleted) {
         lastCompleted=first.completed;
         stack.removeFirst();
         first=peek();
         if(first!=null) {
            curCompleted=first.completed;
         }
      }
   }

   int labelLevel(String label) {
      debug("labelLevel");

      int level = 1; // current level
      for(StatementStackItem i: stack) {
         if( label == null && i.label == null || label !=null && label.equals(i.label) ) {
            return level;
         }
         if( i.type==LOOP || i.type==SWITCH || (i.type==BLOCK && i.label!=null) ) {
            level++;
         }
      }
      return 0; // not found
   }

   int lastLoopLevel() {
      debug("lastLoopLevel");

      int level = 1;; // current level
      for(StatementStackItem i: stack) {
         if( i.type == LOOP ) {
            return level;
         }
         if( i.type==SWITCH || (i.type==BLOCK && i.label!=null) ) {
            level++;
         }
      }
      return 0; // not found
   }

   StatementStackItem peek() {
      return stack.peek();
   }

   // debug

   final boolean debug=false;

   void debug(Object o) {
      if(debug) {
         System.err.println("SS "+o+"\t\t"+this);
      }
   }

   public String toString() {
      StringBuilder sb=new StringBuilder().append("[");
      for(StatementStackItem i: stack) {
         sb.append(i.toString());
      }
      sb.append("]");
      return sb.toString();
   }

}
